package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheLoginUser;
import top.lixunda.ecommerce.server.user.api.entity.db.UserMenuDO;
import top.lixunda.ecommerce.server.user.mapper.UserMenuMapper;
import top.lixunda.ecommerce.server.user.service.IUserMenuService;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户菜单权限视图 服务实现类
 *
 * @author Lixunda
 * @since 2020-04-26
 */
@Service
public class UserMenuServiceImpl extends BaseServiceImpl<UserMenuMapper, UserMenuDO>
        implements IUserMenuService {

    /**
     * 查询当前登陆用户拥有权限的所有菜单目录信息
     *
     * @return 所有菜单目录信息
     */
    @Override
    public List<UserMenuDO> queryAll() {
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        return this.list(new LambdaQueryWrapper<UserMenuDO>()
                .eq(UserMenuDO::getAccount, cacheLoginUser.getAccount())
                .eq(UserMenuDO::getUserType, cacheLoginUser.getType()));
    }

    /**
     * 根据菜单编码查询当前登陆用户拥有权限的某一个子系统的菜单目录
     *
     * @param menuCode 菜单编码，唯一索引
     * @return 该子系统的菜单目录信息
     */
    @Override
    public List<UserMenuDO> queryOneRootAllByCode(String menuCode) {
        if (ObjectValidators.isEmpty(menuCode)) {
            throw getAppException("查询菜单失败！菜单编码不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        UserMenuDO userMenuDO = this.getOne(new LambdaQueryWrapper<UserMenuDO>()
                .eq(UserMenuDO::getMenuCode, menuCode)
                .eq(UserMenuDO::getAccount, cacheLoginUser.getAccount())
                .eq(UserMenuDO::getUserType, cacheLoginUser.getType()), false);
        if (ObjectValidators.isEmpty(userMenuDO)) {
            throw getAppException("查询菜单失败！菜单不存在！");
        }
        if (ObjectValidators.isEmpty(userMenuDO.getParentMenuId()) || userMenuDO.getParentMenuId() <= 0) {
            throw getAppException("查询菜单失败！菜单不是根节点菜单编号！");
        }
        List<UserMenuDO> result = new ArrayList<>(32);
        result.add(userMenuDO);
        List<Integer> parentIdList = Collections.singletonList(userMenuDO.getMenuId());
        while (ObjectValidators.isNotEmpty(parentIdList)) {
            List<UserMenuDO> temp = this.list(new LambdaQueryWrapper<UserMenuDO>()
                    .in(UserMenuDO::getParentMenuId, parentIdList));
            if (ObjectValidators.isEmpty(temp)) {
                result.addAll(temp);
                parentIdList = temp.stream()
                        .map(UserMenuDO::getMenuId)
                        .collect(Collectors.toList());
            }
        }
        return result;
    }

    /**
     * 根据父节点id获取当前登陆用户拥有权限的子类节点列表
     *
     * @param id 父节点id
     * @return 子节点列表
     */
    @Override
    public List<UserMenuDO> queryChildrenByParentId(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("查询子菜单失败！菜单编号不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        // id小于等于零时返回根节点列表
        if (id <= 0) {
            return queryRoots();
        }
        return this.list(
                new LambdaQueryWrapper<UserMenuDO>()
                        .eq(UserMenuDO::getAccount, cacheLoginUser.getAccount())
                        .eq(UserMenuDO::getUserType, cacheLoginUser.getType())
                        .eq(UserMenuDO::getParentMenuId, id));
    }

    /**
     * 查询首层节点，父节点为空或小于等于0
     *
     * @return 首层节点
     */
    @Override
    public List<UserMenuDO> queryRoots() {
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        return this.list(new LambdaQueryWrapper<UserMenuDO>()
                .eq(UserMenuDO::getAccount, cacheLoginUser.getAccount())
                .eq(UserMenuDO::getUserType, cacheLoginUser.getType())
                .isNull(UserMenuDO::getParentMenuId)
                .or().le(UserMenuDO::getParentMenuId, 0));
    }

}
